using System;
using System.Collections.Generic;
using Comdiv.Extensions;
using Comdiv.Model;
using Comdiv.Model.Interfaces;
using Comdiv.Logging;
using Comdiv.Application;
using Comdiv.Persistence;
using Comdiv.Inversion;
using Comdiv.Security.Acl;
using Comdiv.Conversations;
using Comdiv.IO;
using Comdiv.Security;
using System.Linq;
using NHibernate.Criterion;

namespace Comdiv.Messaging{
    /// <summary>
    /// Default NHibernate-base MessageQueryExecutor, no any optimizations
    /// </summary>
    public class DefaultMessageQueryExecutor : MessageQueryExecutorBase{



        public override IEnumerable<IMessage> doQuery(IMessageQuery query){
            IEnumerable<IMessage> result = null;
            if (query.NativeQuery.hasContent()){
                result = Storage.Query(query.NativeQuery);
            }
            else{
                var crit = Container.getCriteria<IMessage>();
                if (!query.ShowInactive){
                    crit.Add(Restrictions.Eq("Active", true));
                }
                if (query.Type.hasContent()){
                    crit.Add(Restrictions.Eq("Type", query.Type));
                }
                if (query.Sender.hasContent()){
                    crit.Add(Restrictions.Eq("Sender", query.Sender));
                }
                if (!query.AnyTarget){
                    var usrDomainBroadCastCondition = Restrictions.Disjunction();
                    if (query.Target.hasContent()){
                        usrDomainBroadCastCondition.Add(Restrictions.Eq("Target", query.Target));
                    }
                    if (query.Domain.hasContent()){
                        usrDomainBroadCastCondition.Add(Restrictions.Eq("Target", query.Domain));
                    }
                    if (query.ShowBroadCasts){
                        usrDomainBroadCastCondition.Add(Restrictions.Eq("Target", ""));
                    }
                    if (query.ShowBroadCasts){
                        crit.Add(usrDomainBroadCastCondition);
                    }
                    else{
                        crit.Add(Restrictions.And(Restrictions.Not(Restrictions.Eq("Target", "")),
                                                  usrDomainBroadCastCondition));
                    }
                }
                result = crit.List<IMessage>();
            }
            return doFilter(query, result);
        }

        protected IMessage[] doFilter(IMessageQuery query, IEnumerable<IMessage> result){
            return result.Where(x =>{
                                    if (!query.ShowArchived){
                                        if (IsArchived(x, query.Usr)){
                                            return false;
                                        }
                                    }
                                    if (!query.ShowReaded){
                                        if (IsReaded(x, query.Usr)){
                                            return false;
                                        }
                                    }
                                    return true;
                                }).ToArray();
        }

        public override void doMarkRead(IMessage message, string usr, bool readed){
            var record = findExistedReadRecord(message, usr);
            if (null == record){
                record = Storage.New<IMessageRead>();
                record.Message = message;
                record.Usr = usr;
            }
            record.IsReaded = readed;
            Storage.Save(record);
        }

        public override void doMarkArchive(IMessage message, string usr, bool archived){
            var record = findExistedArchiveRecord(message, usr);
            if (null == record){
                record = Storage.New<IMessageClose>();
                record.Message = message;
                record.Usr = usr;
            }
            record.IsArchived = archived;
            Storage.Save(record);
        }

        protected virtual IMessageClose findExistedArchiveRecord(IMessage message, string usr){
                if (message.Archives==null) return null;
                return message.Archives.FirstOrDefault(x => ( x.Usr ?? "").ToLower() == usr.ToLower());
            
        }

        public override bool doIsReaded(IMessage message, string usr){
            var record = findExistedReadRecord(message, usr);
            if (null == record){
                return false;
            }
            return record.IsReaded;
        }

        protected virtual IMessageRead findExistedReadRecord(IMessage message, string usr){
            if (message != null){
                if (message.Reads != null){
                    return message.Reads.FirstOrDefault(x => x.Usr.ToLower() == usr.ToLower());
                }
            }
            return null;
        }

        public override bool doIsArchived(IMessage message, string usr){
            var record = findExistedArchiveRecord(message, usr);
            if (null == record){
                return false;
            }
            return record.IsArchived;
        }
    }
}